#include "n32g031.h"
#include "stdio.h"
#include "stdint.h"
#include "cmt_spi3.h"
#include "DevicesDelay.h"
/* ************************************************************************
//
*  ************************************************************************ */
static void set_sdio_read(void);
static void set_sdio_write(void);
static void set_clk_out(void);
static void set_fcsb_out(void);
static void set_csb_out(void);
/* ************************************************************************
*  The following need to be modified by user
*  ************************************************************************ */

#define CMT_SET_CSB()           GPIO_SetBits(CMT_CSB_PORT, CMT_CSB_PIN)
#define CMT_RESET_CSB()         GPIO_ResetBits(CMT_CSB_PORT, CMT_CSB_PIN)

#define CMT_SET_FCSB()          GPIO_SetBits(CMT_FCSB_PORT, CMT_FCSB_PIN)
#define CMT_RESET_FCSB()        GPIO_ResetBits(CMT_FCSB_PORT, CMT_FCSB_PIN)

#define CMT_SET_CLK()           GPIO_SetBits(CMT_CLK_PORT, CMT_CLK_PIN)
#define CMT_RESET_CLK()         GPIO_ResetBits(CMT_CLK_PORT, CMT_CLK_PIN)

#define CMT_SET_SDIO()          GPIO_SetBits(CMT_SDIO_PORT, CMT_SDIO_PIN)
#define CMT_RESET_SDIO()        GPIO_ResetBits(CMT_SDIO_PORT, CMT_SDIO_PIN)

#define cmt_spi3_csb_out()      set_csb_out()
#define cmt_spi3_fcsb_out()     set_fcsb_out()
#define cmt_spi3_sclk_out()     set_clk_out()
#define cmt_spi3_sdio_out()     set_sdio_write()
#define cmt_spi3_sdio_in()      set_sdio_read()

#define cmt_spi3_csb_1()        CMT_SET_CSB()
#define cmt_spi3_csb_0()        CMT_RESET_CSB()

#define cmt_spi3_fcsb_1()       CMT_SET_FCSB()
#define cmt_spi3_fcsb_0()       CMT_RESET_FCSB()

#define cmt_spi3_sclk_1()       CMT_SET_CLK()
#define cmt_spi3_sclk_0()       CMT_RESET_CLK()

#define cmt_spi3_sdio_1()       CMT_SET_SDIO()
#define cmt_spi3_sdio_0()       CMT_RESET_SDIO()
#define cmt_spi3_sdio_read()    GPIO_ReadInputDataBit(CMT_SDIO_PORT, CMT_SDIO_PIN)
/* ************************************************************************ */

static void set_sdio_read()
{
    GPIO_InitType   GPIO_InitStructure;
    RCC_EnableAPB2PeriphClk (RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB , ENABLE);
    GPIO_InitStructure.Pin = CMT_SDIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_INPUT;//GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
    GPIO_InitPeripheral(CMT_SDIO_PORT, &GPIO_InitStructure);
}
static void set_int1_in()
{
    GPIO_InitType   GPIO_InitStructure;
    RCC_EnableAPB2PeriphClk (RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB , ENABLE);
    GPIO_InitStructure.Pin = CMT_INT1_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_INPUT;//GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
    GPIO_InitPeripheral(CMT_INT1_PORT, &GPIO_InitStructure);
}
static void set_int2_in()
{
    GPIO_InitType   GPIO_InitStructure;
    RCC_EnableAPB2PeriphClk (RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB , ENABLE);
    GPIO_InitStructure.Pin = CMT_INT2_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_INPUT;//GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
    GPIO_InitPeripheral(CMT_INT2_PORT, &GPIO_InitStructure);
}
static void set_sdio_write()
{
    GPIO_InitType   GPIO_InitStructure;
    RCC_EnableAPB2PeriphClk (RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB , ENABLE);
    GPIO_InitStructure.Pin = CMT_SDIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
    GPIO_InitPeripheral(CMT_SDIO_PORT, &GPIO_InitStructure);
}

static void set_fcsb_out()
{
    GPIO_InitType   GPIO_InitStructure;
    RCC_EnableAPB2PeriphClk (RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB , ENABLE);
    GPIO_InitStructure.Pin = CMT_FCSB_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
    GPIO_InitPeripheral(CMT_FCSB_PORT, &GPIO_InitStructure);
}

static void set_csb_out()
{
    GPIO_InitType   GPIO_InitStructure;
    RCC_EnableAPB2PeriphClk (RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB , ENABLE);
    GPIO_InitStructure.Pin = CMT_CSB_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
    GPIO_InitPeripheral(CMT_CSB_PORT, &GPIO_InitStructure);
}
static void set_clk_out()
{
    GPIO_InitType   GPIO_InitStructure;
    RCC_EnableAPB2PeriphClk (RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB , ENABLE);
    GPIO_InitStructure.Pin = CMT_CLK_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
    GPIO_InitPeripheral(CMT_CLK_PORT, &GPIO_InitStructure);
}
void cmt_spi3_delay(void)
{
    u32 n = 14;
    while(n--);
}

void cmt_spi3_delay_us(void)
{
    uint16_t n = 16;
    while(n--);
}

void cmt_spi3_init(void)
{
    // PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
    // PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
    set_int2_in();
    set_int1_in();
    cmt_spi3_csb_1();
    cmt_spi3_csb_out();
    cmt_spi3_csb_1();   /* CSB has an internal pull-up resistor */

    cmt_spi3_sclk_0();
    cmt_spi3_sclk_out();
    cmt_spi3_sclk_0();   /* SCLK has an internal pull-down resistor */

    cmt_spi3_sdio_1();
    cmt_spi3_sdio_out();
    cmt_spi3_sdio_1();

    cmt_spi3_fcsb_1();
    cmt_spi3_fcsb_out();
    cmt_spi3_fcsb_1();  /* FCSB has an internal pull-up resistor */

    cmt_spi3_delay();
}

void cmt_spi3_send(uint8_t data8)
{
    uint8_t i;


    for(i=0; i<8; i++)
    {
        cmt_spi3_sclk_0();

        /* Send byte on the rising edge of SCLK */
        if(data8 & 0x80)
            cmt_spi3_sdio_1();
        else
            cmt_spi3_sdio_0();

        cmt_spi3_delay();

        data8 <<= 1;
        cmt_spi3_sclk_1();
        cmt_spi3_delay();
    }
}

uint8_t cmt_spi3_recv(void)
{
    uint8_t i;
    uint8_t data8 = 0xFF;

    for(i=0; i<8; i++)
    {
        cmt_spi3_sclk_0();
        cmt_spi3_delay();
        data8 <<= 1;

        cmt_spi3_sclk_1();

        /* Read byte on the rising edge of SCLK */
        if(cmt_spi3_sdio_read())
            data8 |= 0x01;
        else
            data8 &= ~0x01;

        cmt_spi3_delay();
    }

    return data8;
}

void cmt_spi3_write(uint8_t addr, uint8_t dat)
{

    cmt_spi3_sdio_1();
    cmt_spi3_sdio_out();

    cmt_spi3_sclk_0();
    cmt_spi3_sclk_out();
    cmt_spi3_sclk_0();

    cmt_spi3_fcsb_1();
    cmt_spi3_fcsb_out();
    cmt_spi3_fcsb_1();

    cmt_spi3_csb_0();

    /* > 0.5 SCLK cycle */
    cmt_spi3_delay();
    cmt_spi3_delay();

    /* r/w = 0 */
    cmt_spi3_send(addr&0x7F);

    cmt_spi3_send(dat);

    cmt_spi3_sclk_0();

    /* > 0.5 SCLK cycle */
    cmt_spi3_delay();
    cmt_spi3_delay();

    cmt_spi3_csb_1();

    cmt_spi3_sdio_1();
    cmt_spi3_sdio_in();

    cmt_spi3_fcsb_1();

}

void cmt_spi3_read(uint8_t addr, uint8_t* p_dat)
{

    cmt_spi3_sdio_1();
    cmt_spi3_sdio_out();

    cmt_spi3_sclk_0();
    cmt_spi3_sclk_out();
    cmt_spi3_sclk_0();

    cmt_spi3_fcsb_1();
    cmt_spi3_fcsb_out();
    cmt_spi3_fcsb_1();

    cmt_spi3_csb_0();

    /* > 0.5 SCLK cycle */
    cmt_spi3_delay();
    cmt_spi3_delay();

    /* r/w = 1 */
    cmt_spi3_send(addr|0x80);

    /* Must set SDIO to input before the falling edge of SCLK */
    cmt_spi3_sdio_in();

    *p_dat = cmt_spi3_recv();

    cmt_spi3_sclk_0();

    /* > 0.5 SCLK cycle */
    cmt_spi3_delay();
    cmt_spi3_delay();

    cmt_spi3_csb_1();

    cmt_spi3_sdio_1();
    cmt_spi3_sdio_in();

    cmt_spi3_fcsb_1();

}

void cmt_spi3_write_fifo(const uint8_t* p_buf, uint16_t len)
{
    uint16_t i;

    cmt_spi3_fcsb_1();
    cmt_spi3_fcsb_out();
    cmt_spi3_fcsb_1();

    cmt_spi3_csb_1();
    cmt_spi3_csb_out();
    cmt_spi3_csb_1();

    cmt_spi3_sclk_0();
    cmt_spi3_sclk_out();
    cmt_spi3_sclk_0();

    cmt_spi3_sdio_out();

    for(i=0; i<len; i++)
    {
        cmt_spi3_fcsb_0();

        /* > 1 SCLK cycle */
        cmt_spi3_delay();
        cmt_spi3_delay();

        cmt_spi3_send(p_buf[i]);

        cmt_spi3_sclk_0();

        /* > 2 us */
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();

        cmt_spi3_fcsb_1();

        /* > 4 us */
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
    }

    cmt_spi3_sdio_in();

    cmt_spi3_fcsb_1();

}

void cmt_spi3_read_fifo(uint8_t* p_buf, uint16_t len)
{
    uint16_t i;

    cmt_spi3_fcsb_1();
    cmt_spi3_fcsb_out();
    cmt_spi3_fcsb_1();

    cmt_spi3_csb_1();
    cmt_spi3_csb_out();
    cmt_spi3_csb_1();

    cmt_spi3_sclk_0();
    cmt_spi3_sclk_out();
    cmt_spi3_sclk_0();

    cmt_spi3_sdio_in();

    for(i=0; i<len; i++)
    {
        cmt_spi3_fcsb_0();

        /* > 1 SCLK cycle */
        cmt_spi3_delay();
        cmt_spi3_delay();

        p_buf[i] = cmt_spi3_recv();

        cmt_spi3_sclk_0();

        /* > 2 us */
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();

        cmt_spi3_fcsb_1();

        /* > 4 us */
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
        cmt_spi3_delay_us();
    }

    cmt_spi3_sdio_in();

    cmt_spi3_fcsb_1();

}
